/*
 * Copyright 2018, 2019, 2020 Dooboolab.
 *
 * This file is part of Flutter-Sound.
 *
 * Flutter-Sound is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3 (LGPL-V3), as published by
 * the Free Software Foundation.
 *
 * Flutter-Sound is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Flutter-Sound.  If not, see <https://www.gnu.org/licenses/>.
 */


import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_sound/flutter_sound.dart';

//import '../recording_disposition.dart';
//import '../track.dart';
import 'recorder_playback_controller.dart' as controller;

typedef OnStart = void Function();
typedef OnDelete = void Function();
typedef OnProgress = void Function(RecordedAudio media);
typedef OnStop = void Function(RecordedAudio media);
typedef OnPaused = void Function(RecordedAudio media, bool isPaused);

enum _RecorderState {
  isStopped,
  isRecording,
  isPaused,
}

/// The [requestPermissions] callback allows you to provide an
/// UI informing the user that we are about to ask for a permission.
///
typedef UIRequestPermission = Future<bool> Function(
    BuildContext context, Track track);

/// A UI for recording audio.
class SoundRecorderUI extends StatefulWidget {
  static const int _barHeight = 60;

  final Color backgroundColor;


  /// Callback to be notified when the recording stops
  final OnStop onStopped;

  /// Callback to be notified when the recording starts.
  final OnStart onStart;

  /// Callback to be notified when the recording pause.
  final OnPaused onPaused;

  final OnDelete onDelete;

  /// Stores and Tracks the recorded audio.
  final RecordedAudio audio;

  final bool showTrashCan;

  /// The [requestPermissions] callback allows you to request
  /// the necessary permissions to record a track.
  ///
  /// If [requestPermissions] is null then no permission checks
  /// will be performed.
  ///
  /// It is sometimes useful to explain to the user why we are asking
  /// for permission before showing the OSs permission request.
  /// This callback gives you the opportunity to display a suitable
  /// notice and then request permissions.
  ///
  /// Return [true] to indicate that the user has given permission
  /// to record and that you have made the necessary calls to
  /// grant those permissions.
  ///
  /// If [true] is returned the recording will proceed.
  /// If [false] is returned then recording will not start.
  ///
  /// This method will be called even if we have the necessary permissions
  /// as we make no checks.
  ///
  final UIRequestPermission requestPermissions;

  ///
  /// Records audio from the users microphone into the given media file.
  ///
  /// The user is presented with a UI that allows them to start/stop recording
  /// and provides some basic feed back on the volume as the recording
  ///  progresses.
  ///
  /// The [track] specifies the file we are recording to.
  /// At the moment the [track] must be constructued using [Track.fromFile] as
  /// recording to a databuffer is not currently supported.
  ///
  /// The [onStart] callback is called user starts recording. This method will
  /// be called each time the user clicks the 'record' button.
  ///
  /// The [onStopped] callback is called when the user stops recording. This
  /// method will be each time the user clicks the 'stop' button. It can
  /// also be called if the [stop] method is called.
  ///
  /// The [requestPermissions] callback allows you to request
  /// permissions just before they are required and if desired
  /// display your own dialog explaining why the permissions are required.
  ///
  /// If you do not provide [requestPermissions] then you must ensure
  /// that all required permissions are granted before the
  /// [SoundRecorderUI] widgets starts recording.
  ///
  ///
  /// ```dart
  ///   SoundRecorderIU(track,
  ///       informUser: (context, track)
  ///           {
  ///               // pseudo code
  ///               String reason;
  ///               if (!microphonePermission.granted)
  ///                 reason += 'please allow microphone';
  ///               if (!requestingStoragePermission.granted)
  ///                 reason += 'please allow storage';
  ///               if (Dialog.show(reason) == Dialog.OK)
  ///               {
  ///                 microphonePermission.request == granted;
  ///                 storagePermission.request == granted;
  ///                 return true;
  ///               }
  ///
  ///           });
  ///
  /// ```
  SoundRecorderUI(
    Track track, {
    this.backgroundColor = Colors.blueGrey,
    this.onStart,
    this.onStopped,
    this.onPaused,
    this.onDelete,
    this.requestPermissions,
    this.showTrashCan = true,
    Key key,
  })  : audio = RecordedAudio.toTrack(track),
        super(key: key);

  @override
  State<StatefulWidget> createState() {
    return SoundRecorderUIState(backgroundColor);
  }
}

///
class SoundRecorderUIState extends State<SoundRecorderUI> {

  _RecorderState _state = _RecorderState.isStopped;

  FlutterSoundRecorder _recorder;
  Color backgroundColor;

  ///
  SoundRecorderUIState(Color backgroundColor,) {
     //_recorder.openAudioSession();
    //_recorder.onStarted = _onStarted;
    //_recorder.onStopped = _onStopped;
    this.backgroundColor = backgroundColor;
  }

  @override
  void initState() {
    _recorder =  FlutterSoundRecorder();
    _recorder.openAudioSession(focus: AudioFocus.requestFocusAndDuckOthers).then((toto){controller.registerRecorder(context, this);});
    super.initState();
  }
  @override
  void deactivate( )
  {
    _recorder.stopRecorder();;
    super.deactivate( );
  }

  @override
  Widget build(BuildContext context)  {
    return _buildButtons();
  }

  Widget _buildButtons() {
    return
      GestureDetector(
        onTap: _onTapStartStop,
        child: Container(
            height: ScreenUtil().setHeight(44),
            margin: EdgeInsets.only(
              top: ScreenUtil().setHeight(13),
              bottom: ScreenUtil().setHeight(13),
            ),
            decoration: BoxDecoration(
              color: Color.fromRGBO(214, 178, 128, 1),
              borderRadius: BorderRadius.all(
                Radius.circular(ScreenUtil().setHeight(4)),
              ),
            ),
            child: Row(mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  //SizedBox(width: 20,),
                  Text(_isPaused ? '暂停录音' : _isRecording ? '录音中' : '点击录音',
                      style: TextStyle(
                    fontFamily: 'PingFangSC-Regular',
                    fontSize: ScreenUtil().setSp(16),
                    color: Colors.white,
                  )),

                ],
              //Expanded(child: Column(children: rows))
            )),
      );
  }

  ///
  Stream<RecordingDisposition> get dispositionStream =>
      _recorder.dispositionStream();

  static const _minDbCircle = 15;

  Widget _buildMicrophone() {
    return SizedBox(
        height: 50,
        width: 50,
        child: StreamBuilder<RecordingDisposition>(
            stream: _recorder.dispositionStream(),
            initialData: RecordingDisposition.zero(), // was START_DECIBELS
            builder: (_, streamData) {
              var disposition = streamData.data;
              var min = _minDbCircle;
              if (disposition.decibels == 0) min = 0;
              //      onRecorderProgress(context, this, disposition.duration);
              return Stack(alignment: Alignment.center, children: [
                Visibility (
                  visible: _isRecording || _isPaused,
                child: AnimatedContainer(
                    duration: Duration(milliseconds: 20),
                    // + MIN_DB_CIRCLE so the animated circle is always a
                    // reasonable size (db ranges is typically 45 - 80db)
                    width: disposition.decibels + min,
                    height: disposition.decibels + min,
                    constraints: BoxConstraints(
                        maxHeight: 80.0 + min, maxWidth: 80.0 + min),
                    decoration:
                        BoxDecoration(shape: BoxShape.circle, color: Colors.red),
                  ),
                ),
                InkWell(onTap: _onTapStartStop, child: Icon(_isStopped ? Icons.brightness_1 : Icons.stop, color: _isStopped ? Colors.red : Colors.black),),
              ]);
            }));
  }

  Widget _buildStartStopButton() {
    return  SizedBox(
        height: 50,
        width: 30,
        child:InkWell(
        onTap: _isStopped ? null : (_isPaused ? _resume : _pause),
        child: Icon(
          !_isPaused ?  Icons.pause :  Icons.play_arrow  ,
          //size: 30,
          color: !_isStopped ? Colors.black : Colors.grey,
        )));
  }

  Widget _buildTrashButton() {
    return  SizedBox(
        height: 50,
        width: 30,
        child:InkWell(
            onTap: _isStopped && widget.onDelete != null ? widget.onDelete : null,
            child: Icon(
               Icons.delete_outline  ,
              //size: 30,
              color: _isStopped && widget.onDelete != null ? Colors.black : Colors.grey,
            )));
  }



  void _onTapStartStop() {
    if (_isRecording || _isPaused) {
      _stop();
    } else {
      _onRecord();
    }
  }

  bool get _isRecording => _state == _RecorderState.isRecording;
  bool get _isPaused => _state == _RecorderState.isPaused;
  bool get _isStopped => _state == _RecorderState.isStopped;

  void dispose() {

    _recorder.closeAudioSession();
    super.dispose();
  }

  /// The [stop] methods stops the recording and calls
  /// the [onStopped] callback.
  ///
  void stop() {
    _stop();
  }

  void pause() {
    _pause();
  }

  void resume() {
    _resume();
  }


  void _onRecord() async {
    if (!_isRecording) {
      await _recorder.startRecorder(toFile: widget.audio.track.trackPath);
      _onStarted(wasUser: true);

      //Log.d(widget.audio.track.identity);
    }
  }
  void _stop() async {
    if (_recorder.isRecording || _recorder.isPaused) {
      await _recorder.stopRecorder();
      _onStopped(wasUser: true);
    }
  }


  void _pause() async {
    if (_recorder.isRecording) {
      await _recorder.pauseRecorder();
      _onPaused(wasUser: true);
    }
  }


  void _resume() async{
    if (_recorder.isPaused) {
      await _recorder.resumeRecorder();
      _onResume(wasUser: true);
    }
  }


  /// as recording progresses we update the media's duration.
  void _updateDuration(Duration duration) {
    widget.audio.duration = duration;
  }

  void _onStarted({bool wasUser}) async {
    //Log.d(green('started Recording to: '
        //'${await (await widget.audio).track.identity})'));

    setState(() {
      _state = _RecorderState.isRecording;

      if (widget.onStart != null) {
        widget.onStart();
      }

      controller.onRecordingStarted(context);
    });
  }

  void _onStopped({bool wasUser}) {
    setState(() {
      // TODO _updateDuration(_recorder.duration);
      _state = _RecorderState.isStopped;

      if (widget.onStopped != null) {
        widget.onStopped(widget.audio);
      }

      controller.onRecordingStopped(context, Duration(milliseconds: 2000)); // TODO
    });
  }


  void _onPaused({bool wasUser}) async {
    //Log.d(green('started Recording to: '
    //'${await (await widget.audio).track.identity})'));

    setState(() {
      _state = _RecorderState.isPaused;

      if (widget.onPaused != null) {
        widget.onPaused(widget.audio, true);
      }

      controller.onRecordingPaused(context);
    });
  }


  void _onResume({bool wasUser}) async {
    //Log.d(green('started Recording to: '
    //'${await (await widget.audio).track.identity})'));

    setState(() {
      _state = _RecorderState.isRecording;

      if (widget.onPaused != null) {
        widget.onPaused(widget.audio, false);
      }

      controller.onRecordingResume(context);
    });
  }

}
